用 generator 作弊完後,我們要開始用走一次手寫的流程,先從 Schema 開始,
大部分的 Schema 會對應一張資料庫的表格,我們上次用 generator 產生的 Blog.Notes.Note 這個 Schema 就是對應我們的 notes 表格,裡面寫上表格有的欄位內容、與驗證方式。
這篇會分成幾個段落
Migration 檔案是紀錄專案資料庫變更的指令檔案,並有依照時間排序,他被放在 priv/repo/migrations
資料夾內,目前我們已經有一個 20220911090807_create_notes.exs
的檔案,檔名前面的數字是時間戳記,加上我們待會要新增的就會變兩個,有了 migration 檔案後,如果我們要在另一台電腦下載專案或是有另一個人要一起協作,就可以執行 mix ecto.migrate
一次依照順序執行所有的 migration 讓資料庫跑到最新的狀態。
當然我們不需要自己手打時間戳記,我們可以用 ecto 提供拿來產生 migration 檔案的 generator (好拉還是用一下),產生一個空的 migration 檔案
mix ecto.gen.migration create_posts
產生了 priv/repo/migrations/20220912131338_create_posts.exs
檔案
內容如下
defmodule Blog.Repo.Migrations.CreatePosts do
use Ecto.Migration
def change do
end
end
中間那個 change 方法就是要寫我們這次要做的事情,
第二行的 use Ecto.Migration
裡面的 Ecto.Migration 則是包含了我們在 migration 裡面會用到的方法,
我們來看一下 這個模組的文件 看有什麼我們這次需要的,
一進去是這個模組的說明,點左邊這個模組底下的 Functions 列表
裡面有一個 create 方法這個感覺是我們要用的,他的兩個變數的同名方法裡面的範例看起來就是我們要的,而且剛好也是 posts
create table(:posts) do
add :title, :string, default: "Untitled"
add :body, :text
timestamps()
end
看到這邊就算還沒寫過也可以猜到,裡面的 add 方法是為要新增的 posts 表格建立欄位,範例裡面有 標題欄位 title 與 內容欄位 body,
title 的 add 他的範例有另外加上一個 default 值,其他的選項也可以在這個方法的文件看到,我們這次先不用加。
另外下面有一個 timestamps() 方法,這個方法是要幫我們加上兩個時間欄位用的,照慣例我們每一張表都會有的 inserted_at 與 updated_at 欄位分別來紀錄該筆資料第一次輸入日期時間與更改時間。
整個放進去之後變成這樣
存擋之後來跑跑看吧!
mix ecto.migrate
剛剛新增好的資料庫表格,雖然可以直接從 Phoenix 用 Ecto 操作,但是相當不方便,
在終端機使用 iex 的加強版
iex -S mix
這個會載入目前的 mix 專案,可以在這邊呼叫專案的模組們
在裡面貼上這些來輸入一些項目讓我們方便操作
```elixir
# 在 iex -S mix 裡面
Blog.Repo.insert_all("posts", [
[
title: "文章A",
body: "文章A的內容",
inserted_at: DateTime.utc_now(),
updated_at: DateTime.utc_now()
],
[
title: "文章B",
body: "文章B的內容",
inserted_at: DateTime.utc_now(),
updated_at: DateTime.utc_now()
],
[
title: "文章C",
body: "文章C的內容",
inserted_at: DateTime.utc_now(),
updated_at: DateTime.utc_now()
]
])
沒有寫 schema 的情況,我們時間欄位要自己弄,也沒有任何驗證功能。
query 看看
# 在 iex -S mix 裡面
import Ecto.Query
Blog.Repo.all(from("posts", where: [title: "文章C"], select: [:title, :body]))
回傳
# 在 iex -S mix 執行 query 的回傳 log
iex(10)> Blog.Repo.all(from("posts", where: [title: "文章C"], select: [:title, :body]))
[debug] QUERY OK source="posts" db=0.4ms queue=1.0ms idle=1338.2ms
SELECT p0."title", p0."body" FROM "posts" AS p0 WHERE (p0."title" = '文章C') []
↳ anonymous fn/4 in :elixir.eval_external_handler/1, at: src/elixir.erl:298
[%{body: "文章C的內容", title: "文章C"}]